import 'dart:async';
import 'package:bluetooth_flutter_plugin/src/bluetooth_helper/bluetooth_adapter_base.dart';
import 'package:bluetooth_flutter_plugin/src/bluetooth_helper/bluetooth_connect_state.dart';
import 'package:bluetooth_flutter_plugin/src/bluetooth_helper/bluetooth_interceptor.dart';
import 'package:bluetooth_flutter_plugin/src/bluetooth_helper/bluetooth_send_handler.dart';
import 'package:bluetooth_flutter_plugin/src/bluetooth_helper/bluetooth_service_adapter.dart';
import 'package:bluetooth_flutter_plugin/src/bluetooth_helper/handler_bluetooth_device.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';

/*

这段代码定义了一个名为 `BluetoothManager` 的 Dart 类，用于管理蓝牙设备的扫描、连接和数据传输。以下是代码的概要：

- **单例模式**：`BluetoothManager` 类使用单例模式，确保只有一个实例存在。
- **StreamController**：用于管理蓝牙连接状态的流。
- **扫描设备**：提供了 `startScan` 和 `stopScan` 方法，用于开始和停止扫描蓝牙设备。
- **连接设备**：提供了 `connectDevice` 方法，用于连接到指定的蓝牙设备。
- **断开连接**：提供了 `disconnect` 方法，用于断开当前连接的蓝牙设备。
- **读写数据**：提供了 `write` 和 `read` 方法，用于向蓝牙设备写入和读取数据。
- **扫描结果处理**：通过 `_scanSubscription` 监听扫描结果，并根据需要过滤和处理扫描到的设备。
- **缓存读取值**：使用 `_readCache` 缓存读取的蓝牙数据。
- **超时处理**：在扫描和连接过程中设置了超时处理。

该类还包含一些辅助方法，如 `_hasRequiredServices` 用于检查设备是否包含所需的服务，
`_cancelScanningSubscription` 用于取消扫描订阅，
`_scanningHasStopped` 用于检查扫描是否已停止。

 */

// 扫码的设备回调
typedef CallbackScanResults = void Function(List<ScanResult>);

// 请求的回调
typedef CallbackResponse = void Function(List<int>);

/*
 * 蓝牙管理器 - 单例模式
 */
class BluetoothManager {
  // 单例
  static final BluetoothManager _instance = BluetoothManager._internal();
  factory BluetoothManager() => _instance;
  BluetoothManager._internal() {
    _initialized();
  }

  // 获取 Stream 对象 <BluetoothConnectState>
  Stream<BluetoothConnectState> get bluetoothConnectState =>
      _connectStateController.stream;

  // 蓝牙当前状态
  BluetoothConnectState get bluetoothCurrentState => _bluetoothCurrentState;

  // 获取已连接设备
  BluetoothDevice? get connectedDevice => _handlerBluetoothDevice.device;

  // 通知监听器
  Stream<List<int>>? get _notifyStream => _handlerBluetoothDevice.notifyStream;

  // 创建一个 StreamController，类型为 BluetoothConnectState
  final _connectStateController =
      StreamController<BluetoothConnectState>.broadcast();

  // 蓝牙当前状态
  BluetoothConnectState _bluetoothCurrentState = BluetoothConnectState.idle;

  // 处理的蓝牙设备
  HandlerBluetoothDevice _handlerBluetoothDevice = HandlerBluetoothDevice();

  // 扫描订阅
  StreamSubscription<List<ScanResult>>? _scanSubscription;

  // 蓝牙设备列表
  final List<ScanResult> _scanResultList = [];

  // 扫描超时时长
  static const Duration _scanTimeout = Duration(seconds: 15);

  // 连接超时时长
  static const Duration _connectTimeout = Duration(seconds: 10);

  // 数据响应监听已开启
  bool _notifyEnabled = false;

  // 初始化
  _initialized() {
    FlutterBluePlus.setOptions(showPowerAlert: false);
    // 蓝牙连接状态
    bluetoothConnectState.listen((event) {
      _bluetoothCurrentState = event;
      switch (event) {
        case BluetoothConnectState.connected:
          break;
        default:
          _notifyEnabled = false;
          _handlerBluetoothDevice.device = null;
          break;
      }
      debugPrint("【$runtimeType】蓝牙连接状态: $event");
    });
  }

  // 开始扫描【目标】蓝牙设备。
  Future<bool> search(
    BluetoothDevice targetBluetoothDevice, {
    Duration? timeout,
  }) {
    final controller = StreamController<bool>();
    startScan(
      timeout: timeout,
      onTimeout: () => controller.sink.add(false),
      callbackScanResults: (List<ScanResult> scanResults) {
        for (var result in scanResults) {
          if (result.device.remoteId == targetBluetoothDevice.remoteId) {
            controller.sink.add(true);
          }
        }
      },
    );
    return controller.stream.first;
  }

  /// 开始扫描蓝牙设备。
  ///
  /// [timeout] 指定扫描设备的持续时间。
  /// [callbackScanResults] 是一个回调函数，传递找到的设备列表。
  /// [filterDuplicate] 是否过滤重复蓝牙设备。
  Future<void> startScan({
    Duration? timeout,
    VoidCallback? onTimeout,
    List<Guid>? serviceUuids,
    CallbackScanResults? callbackScanResults,
    bool filterDuplicate = true,
  }) async {
    // 检查设备是否支持蓝牙
    if (!await FlutterBluePlus.isSupported ||
        await FlutterBluePlus.adapterState.first != BluetoothAdapterState.on) {
      _connectStateController.add(BluetoothConnectState.unavailable);
      throw Exception('Bluetooth is not supported or not turned on');
    }
    // 取消之前的扫描订阅
    _cancelScanningSubscription();
    // 清空设备列表
    _scanResultList.clear();

    debugPrint('【$runtimeType】开始扫描蓝牙设备');
    _connectStateController.add(BluetoothConnectState.isScanning);

    // 监听扫描结果
    _scanSubscription =
        FlutterBluePlus.scanResults.listen((List<ScanResult> results) async {
      for (ScanResult result in results) {
        if (_hasRequiredServices(result, serviceUuids ?? [])) {
          if (filterDuplicate) {
            if (!_scanResultList.contains(result)) {
              _scanResultList.add(result);
            }
          } else {
            _scanResultList.add(result);
          }
        }
      }
      // 回调扫描到的设备
      if (callbackScanResults != null && (!_scanningHasStopped())) {
        callbackScanResults(_scanResultList);
      }
    });

    // 开始扫描
    await FlutterBluePlus.startScan(withServices: serviceUuids ?? []);

    // 设置超时
    Future.delayed(timeout ?? _scanTimeout, () async {
      if (_scanningHasStopped()) return;
      debugPrint('【$runtimeType】扫描超时');
      // 超时回调
      if (onTimeout != null) {
        onTimeout();
      }
      // 扫描结束
      await stopScan();
    });
  }

  // 停止扫描
  Future<void> stopScan() async {
    if (_scanningHasStopped()) return;
    _cancelScanningSubscription();
    _connectStateController.add(BluetoothConnectState.idle);
    debugPrint('【$runtimeType】停止扫描');
    return FlutterBluePlus.stopScan();
  }

  // 连接设备
  Future<void> connectDevice<T extends BluetoothAdapterBase>(
    BluetoothDevice device,
    T bluetoothAdapter, {
    Duration? timeout,
  }) async {
    try {
      // 停止扫描
      await stopScan();
      // 断开连接
      await disconnect();
      debugPrint('【$runtimeType】连接设备: ${device.advName} (${device.remoteId})');
      // 连接中
      _connectStateController.add(BluetoothConnectState.connecting);
      // 连接设备
      await device.connect().timeout(
        timeout ?? _connectTimeout,
        onTimeout: () {
          throw TimeoutException('Connection timeout');
        },
      );

      // 适配服务和特征
      _handlerBluetoothDevice = await ServiceCharacteristicsAdapter(
        device,
        bluetoothAdapter,
        await device.discoverServices(),
      ).adapter();

      // 连接成功
      _connectStateController.add(BluetoothConnectState.connected);
    } catch (e) {
      disconnect();
      throw Exception(
          'Connection failed for device ${device.advName} (${device.remoteId}): ${e.toString()}');
    }
  }

  // 断开连接
  Future<void> disconnect() async {
    if (_handlerBluetoothDevice.device != null) {
      _connectStateController.add(BluetoothConnectState.disconnected);
      await _handlerBluetoothDevice.device!.disconnect();
      debugPrint('【$runtimeType】断开连接');
    }
  }

  // 【 写 】蓝牙数据
  Future<List<int>>
      write<S extends BluetoothSendHandler, T extends BluetoothInterceptor>(
    S bluetoothSendHandler,
    List<int> data, {
    bool withoutResponse = false,
    T? bluetoothInterceptor,
  }) async {
    if (_bluetoothCurrentState != BluetoothConnectState.connected ||
        connectedDevice == null ||
        _handlerBluetoothDevice.bluetoothWriteCharacteristic == null) {
      throw Exception(
          'Write failed for device ${connectedDevice?.advName} (${connectedDevice?.remoteId}): $_bluetoothCurrentState - ${_handlerBluetoothDevice.bluetoothWriteCharacteristic}');
    }
    // 添加请求响应通知
    if (!_notifyEnabled) {
      _notify(
        bluetoothSendHandler,
        bluetoothInterceptor: bluetoothInterceptor,
      );
    }
    // 消息id
    String msgId = '';
    // 请求数据 (可拦截处理)
    if (bluetoothInterceptor != null) {
      // 拦截处理
      List<int> reqData = bluetoothInterceptor.requestInterception(data);
      // 写入数据
      msgId = bluetoothSendHandler.getRequestMsgId(reqData);
      _write(bluetoothSendHandler, reqData, withoutResponse: withoutResponse);
    } else {
      // 写入数据
      msgId = bluetoothSendHandler.getRequestMsgId(data);
      _write(bluetoothSendHandler, data, withoutResponse: withoutResponse);
    }
    // 判断msgId是否存在
    if (bluetoothSendHandler.responseStreamMap.keys.contains(msgId)) {
      throw Exception(
          'Write failed for device ${connectedDevice?.advName} (${connectedDevice?.remoteId}): Request ID $msgId already exists');
    }
    StreamController<List<int>> controller = StreamController();
    bluetoothSendHandler.responseStreamMap[msgId] = controller;
    return controller.stream.first;
  }

  // 通知
  _notify<S extends BluetoothSendHandler, T extends BluetoothInterceptor>(
    S bluetoothSendHandler, {
    T? bluetoothInterceptor,
    bool withoutResponse = false,
  }) {
    _notifyEnabled = true;

    // 监听写后的响应
    _notifyStream?.listen((data) {
      // 处理响应数据
      if (bluetoothInterceptor != null) {
        // 拦截处理
        List<int> rspData = bluetoothInterceptor.responseInterception(data);
        // 响应数据
        _handleNotify(bluetoothSendHandler, rspData,
            bluetoothSendHandler.getResponseMsgId(rspData));
      } else {
        // 响应数据
        _handleNotify(bluetoothSendHandler, data,
            bluetoothSendHandler.getResponseMsgId(data));
      }
      // 支持并发请求
      if (bluetoothSendHandler.requestQueue.isNotEmpty) {
        if (bluetoothSendHandler.supportsConcurrentRequests) {
          // 请求列表
          List<List<int>> requestList =
              bluetoothSendHandler.requestQueue.toList();
          List<int> nextReqList = [];
          List<List<int>> removedList = [];
          for (var reqItem in requestList) {
            if (nextReqList.length + reqItem.length <=
                bluetoothSendHandler.concurrentRequestsMaxLength) {
              nextReqList.addAll(reqItem);
              removedList.add(reqItem);
            }
          }
          requestList.removeWhere((item) => removedList.contains(item));
          // 更新请求队列
          bluetoothSendHandler.requestQueue.clear();
          bluetoothSendHandler.requestQueue.addAll(requestList);
          // 写入数据
          _write(
            bluetoothSendHandler,
            nextReqList,
            withoutResponse: withoutResponse,
          );
        } else {
          List<int> nextReqList =
              bluetoothSendHandler.requestQueue.removeFirst();
          // 写入数据
          _write(
            bluetoothSendHandler,
            nextReqList,
            withoutResponse: withoutResponse,
          );
        }
      } else {
        debugPrint('【$runtimeType】✅ 无等待请求');
      }
    });
  }

  // 通知数据处理
  _handleNotify<S extends BluetoothSendHandler>(
    S bluetoothSendHandler,
    List<int> data,
    String msgId,
  ) {
    debugPrint('【$runtimeType】Notify Data: $data');
    StreamController<List<int>>? controller =
        bluetoothSendHandler.responseStreamMap[msgId];
    if (controller != null) {
      controller.add(data);
      bluetoothSendHandler.responseStreamMap.remove(msgId);
    }
  }

  // 写入数据
  _write<S extends BluetoothSendHandler>(
    S bluetoothSendHandler,
    List<int> data, {
    bool withoutResponse = false,
  }) {
    send() {
      _handlerBluetoothDevice.bluetoothWriteCharacteristic!
          .write(data, withoutResponse: withoutResponse);
    }

    // 支持并发请求
    if (bluetoothSendHandler.supportsConcurrentRequests) {
      if (bluetoothSendHandler.requestQueue.isEmpty) {
        // 队列为空，直接写入
        send();
      } else {
        // 请求加入队列
        bluetoothSendHandler.requestQueue.add(data);
      }
    } else {
      send();
    }
  }

  // 【 读 】蓝牙数据
  Future<List<int>> read(BluetoothCharacteristic characteristic) async {
    throw Exception('Read unsupported');
  }

  // 检查设备是否包含所需的服务
  bool _hasRequiredServices(ScanResult result, List<Guid> serviceUuids) {
    if (result.advertisementData.advName.isEmpty) {
      return false;
    } else {
      if (serviceUuids.isEmpty) {
        return true;
      } else {
        return result.advertisementData.serviceUuids
            .any((uuid) => serviceUuids.contains(uuid));
      }
    }
  }

  // 取消扫描订阅
  void _cancelScanningSubscription() {
    _scanSubscription?.cancel();
    _scanSubscription = null;
    debugPrint('【$runtimeType】取消扫描订阅');
  }

  // 扫描已停止
  bool _scanningHasStopped() => _scanSubscription == null;
}
